<?php
/**
 * | 节程 [ 节程赋能开发者，助力企业发展 ]
 * +----------------------------------------------------------------------
 *  | Copyright (c) 2020~2029 温州惊蛰网络科技有限公司 All rights reserved.
 * +----------------------------------------------------------------------
 *  | Licensed 节程并不是自由软件，未经许可不能去掉节程相关版权
 * +----------------------------------------------------------------------
 */


namespace app\index\service;

use app\index\controller\Url;
use app\index\model\Agent;
use app\index\model\UserWx;
use app\madmin\model\MallLog;
use app\utils\SendMsg;
use app\index\model\Assistant;
use app\index\model\AgentApply;
use app\index\model\User as UserModel;
use app\index\model\Configuration;
use app\index\model\User;
use app\index\model\UserCash;
use think\Exception;
use think\facade\Cache;
use app\utils\Wechat;

class LoginService
{


    public function getSmsCode(int $mobile): array
    {
        $code = rand(100000, 999999);
        $msgData['verification_code'] = $code;
        Cache::set(checkRedisKey((string)$mobile), $code, 300);
        $sendMsg = new SendMsg("用户进行绑定手机号时发送");
        $sendMsg->send((object)['mobile' => $mobile, 'userWx' => (object)['type' => 3]], $msgData);
        return [HTTP_SUCCESS, '发送成功'];
    }


    public function verificationSmsCode(string $mobile, string $code): array
    {
        $cahce_code = Cache::get(checkRedisKey((string)$mobile));
        if ($cahce_code == $code)
            return [HTTP_SUCCESS, '正确'];
        return [HTTP_INVALID, '错误'];
    }


    public function getUserOpenId(array $data, array $js): array
    {

        if (array_key_exists('unionid', $data)) {
            $unionid = UserWx::where('unionid', '=', $data['unionid'])->where('mall_id', $data['mid'])->find();
            $openid = null;
        } else {
            $openid = UserWx::where('openid', '=', $data['openid'])->where('mall_id', $data['mid'])->find();
            $unionid = null;
        }
        $flag = false;
        if (empty($openid) && empty($unionid)) {
            $res = $this->subscribe($data['openid'], array_merge($js, $data));
            $res['nickname']=preg_replace('/[\x{10000}-\x{10FFFF}]/u','',$res['nickname']);
            $arr = ['nickname' => $res['nickname'], 'picurl' => $this->setHeadUrl($res['headimgurl']), 'mall_id' => $data['mid'], 'subscribe' => $res['subscribe']];
            $create = UserModel::create($arr);
            $list = ['openid' => $res['openid'], 'type' => 2, 'user_id' => $create->id, 'mall_id' => $data['mid'], 'unionid' => $res['unionid'] ?? null, 'sex' => $res['sex'] ?? null];
            UserWx::create($list);
            $arr['id'] = $create->id;
            UserCash::create(['user_id' => $create->id, 'mall_id' => $data['mid']]);
            $userInfo = $arr;
            $userInfo['status'] = 1;
            if (isset($data['pid'])) $this->bindAgent(array_merge($userInfo, $data), $data['mid']);
            $pid = isset($data['pid']) ? $data['pid'] : 0;
            $this->agentRegister($userInfo, $pid);
            $flag = true;
        } elseif (!empty($openid) && empty($unionid)) {
            if (array_key_exists('unionid', $data)) UserWx::where('openid', $openid['openid'])->where('mall_id', $data['mid'])->update(['unionid' => $data['unionid']]);
            $userInfo = UserModel::where('id', $openid['user_id'])->find()->toArray();
        } else {
            $where[] = array_key_exists('unionid', $data) ? ['unionid', '=', $unionid['unionid']] : ['openid', '=', $openid['openid']];
            $wx = UserWx::where($where)->find();
            $userInfo = UserModel::where('id', $wx['user_id'])->find()->toArray();
        }
        $token = createToken();
        $assistant = Assistant::where(['user_id' => $userInfo['id'], 'status' => 1])->find();
        $userInfo['is_write'] = isset($assistant) ? true : false;
        Cache::store('redis')->set("TOKEN:" . $userInfo['id'], $token, 60 * 60 * 24 * 30);

        Cache::store('redis')->set("INDEX:" . $token . "-" . $data['mid'], json_encode($userInfo), 60 * 60 * 24 * 30);
        if (empty($userInfo['subscribe']) && !$flag) $this->updateSubscribe($data['openid'], array_merge($js, $data), $userInfo['id']);

        return [HTTP_SUCCESS, $token];
    }

    public function saveUserInfo(array $data)
    {
        try{
            $conf = Configuration::where('type', 'wxa')->value('configuration');
            $js = json_decode($conf, true);
            $id = base64_decode($data['user_id']);
            $session_key = Cache::store('redis')->get(checkRedisKey("INDEX:" . $id));
            $list = $this->decryptData($js['appid'], $session_key, $data['encryptedData'], $data['iv']);
            $js = json_decode($list, true);
            $picurl = 'https://mmbiz.qpic.cn/mmbiz/icTdbqWNOwNRna42FI242Lcia07jQodd2FJGIYQfG0LAJGFxM4FbnQP6yfMxBgJ0F3YRqJCJ1aPAK2dQagdusBZg/0';
            if ($js['nickName'] == "微信用户" && $js['avatarUrl'] == $picurl) {
                $js['nickName'] = "小程序_". time() . rand(10, 99);
            } else {
                $js['nickName'] = preg_replace('/[\x{10000}-\x{10FFFF}]/u','',$js['nickName']);
            }

            UserModel::update(['nickname' => $js['nickName'], 'picurl' => $this->setHeadUrl($js['avatarUrl']), 'mall_id' => $data['mid']], ['id' => base64_decode($data['user_id'])]);
            $res = UserModel::with('userWx')->find(base64_decode($data['user_id']))->toArray();
            $res['token'] = createToken();
            $res['id'] = $id;
            $flag = Agent::where('user_id', $id)->find();

            if (empty($flag)) $this->agentRegister((array)$res);
            $assistant = Assistant::where(['mall_id' => $data['mid'], 'user_id' => $res['id'], 'status' => 1])->find();
            $res['is_write'] = isset($assistant) ? true : false;
            Cache::store('redis')->set(checkRedisKey("TOKEN:" . $id), $res['token'], 60 * 60 * 24 * 30);
            Cache::store('redis')->set("INDEX:" . $res['token'] . "-" . $data['mid'], json_encode($res), 60 * 60 * 24 * 30);
            return [HTTP_SUCCESS, $res];
        }catch (\Exception $e){
            return [HTTP_NOTACCEPT, $e->getMessage()];
        }


    }

    public function getUserInfo(array $js, string $pid = null)
    {
        if (array_key_exists('unionid', $js)) {
            $unionid = UserWx::where('unionid', $js['unionid'])->where('mall_id', $js['mid'])->find();
            $openid = null;
        } else {
            $openid = UserWx::where('openid', $js['openid'])->where('mall_id', $js['mid'])->find();
            $unionid = null;
        }
        if (empty($openid) && empty($unionid)) {
            $res = UserModel::create(['status' => 1, 'pid' => $pid, 'mall_id' => $js['mid']]);
            UserWx::create(['openid' => $js['openid'], 'type' => 1, 'user_id' => $res->id, 'unionid' => $js['unionid'] ?? null, 'sex' => $res['sex'] ?? null, 'mall_id' => $js['mid']]);
            UserCash::create(['user_id' => $res->id, 'mall_id' => $js['mid']]);
        } elseif ($openid && !$unionid) {
            UserWx::where('openid', $openid['openid'])->where('mall_id', $js['mid'])->update(['unionid' => $js['unionid'] ?? null]);
            $res = User::where('id', $openid['user_id'])->where('mall_id', $js['mid'])->find();
        } else {
            $where[] = array_key_exists('unionid', $js) ? ['unionid', '=', $js['unionid']] : ['openid', '=', $js['openid']];
            $wx = UserWx::where($where)->where('mall_id', $js['mid'])->find();
            $res = UserModel::where('id', $wx['user_id'])->where('mall_id', $js['mid'])->find();
        }
        Cache::store('redis')->set(checkRedisKey("INDEX:" . $res['id']), $js['session_key'], 60 * 60 * 24);
        $id = $res->id;
        unset($res['openid'], $res['id']);
        $res['user_id'] = base64_encode(trim($id));
        return [HTTP_SUCCESS, $res];
    }


    public function getUserPhone(array $data)
    {
        global $token;
        try{
            if (!isset($token)) $token = request()->header('Authorization');
            $conf = Configuration::where('type', 'wxa')->value('configuration');
            $js = json_decode($conf, true);
            $id = $data['user_id'];
            $session_key = Cache::store('redis')->get(checkRedisKey("INDEX:" . $id));
            $list = $this->decryptData($js['appid'], $session_key, $data['encryptedData'], $data['iv']);
            $new_data=array_merge($data,['js'=>$js['appid'],'session_key'=>$session_key]);
            $js = json_decode($list, true);
            file_put_contents(public_path()."1.txt",$list.PHP_EOL,FILE_APPEND);
            file_put_contents(public_path()."2.txt",json_encode($new_data).PHP_EOL,FILE_APPEND);
            if (!isset($js['purePhoneNumber'])) throw new Exception("获取手机号码失败！", HTTP_UNAUTH);
            User::update(['mobile' => $js['purePhoneNumber']], ['id' => $id]);
            $find = UserModel::find($id);
            Cache::store('redis')->delete("INDEX:" . $token . "-" . $find['mall_id']);
            Cache::store('redis')->set("INDEX:" . $token . "-" . $find['mall_id'], json_encode($find), 60 * 60 * 24 * 30);
        }catch (\Exception $e){
            throw new Exception($e->getMessage(), HTTP_NOTACCEPT);
        }
        return [HTTP_SUCCESS, $list];
    }

    public function getPhone($code, $user_id)
    {
        $token = Wechat::getAccessToken();
        $url = 'https://api.weixin.qq.com/wxa/business/getuserphonenumber?access_token='.$token;
        $result = wx_request('post', $url, ['code' => $code], ['Content-Type' => 'application/json']);
        if ($result['errcode'] == 0 && isset($result['phone_info']['phoneNumber'])) {
            User::update(['mobile' => $result['phone_info']['phoneNumber']], ['id' => $user_id]);
            $find = UserModel::find($user_id);
            Cache::store('redis')->delete("INDEX:" . $token . "-" . $find['mall_id']);
            Cache::store('redis')->set("INDEX:" . $token . "-" . $find['mall_id'], json_encode($find), 60 * 60 * 24 * 30);
        } else {
            MallLog::create([
                'action' => 'app/index/service/LoginService/:getPhone',
                'message' => "获取手机号错误",
                'data' => serialize($result),
                'time' => date("Y-m-d H:i:s", time())
            ]);
            return [HTTP_NOTACCEPT, "获取手机号码失败！"];
        }
        return [HTTP_SUCCESS, $result];
    }

    public function getTokenUser(string $token)
    {
        if (Cache::store('redis')->has('INDEX:' . $token)) {
            $info = Cache::store('redis')->get('INDEX:' . $token);
            $js = json_decode($info, true);
            return [HTTP_SUCCESS, $js];
        } else {
            return [HTTP_UNPROCES, "请先登录"];
        }
    }

    private function decryptData($appid, $sessionKey, $encryptedData, $iv)
    {

        if (strlen($sessionKey) != 24) {
            return ErrorCode::$IllegalAesKey;
        }

        $aesKey = base64_decode($sessionKey);
        if (strlen($iv) != 24) {
            return ErrorCode::$IllegalIv;
        }
        $aesIV = base64_decode($iv);

        $aesCipher = base64_decode($encryptedData);

        $result = openssl_decrypt($aesCipher, "AES-128-CBC", $aesKey, 1, $aesIV);

        $dataObj = json_decode($result);
        if ($dataObj == NULL) {
            return ErrorCode::$IllegalBuffer;
        }
        if ($dataObj->watermark->appid != $appid) {
            return ErrorCode::$IllegalBuffer;
        }
        return $result;
    }


    public function agentRegister(array $data, int $pid = 0)
    {

        $config = Configuration::where('type', 'agentExplain')->find()->toArray();
        if(empty($config['configuration']['open'])){
            return False;
        }

        if (empty($config['configuration']['become']['type'])) {
            $data = [
                'mall_id' => $data['mall_id'],
                'user_id' => $data['id'],
                'pid' => $pid,
                "mobile" => $data['mobile'] ?? '',
                'name' => $data['nickname']];
            if (empty($config['configuration']['isAudit'])) {
                $user=User::where(['id'=>$data['user_id']])->find();
                $pid=!empty($user->pid) ? $user->pid : $pid;
                $data['pid']=$pid ?? 0;
                $create = Agent::create($data);
                if($user){
                    $user->agent_id=$create->id;
                    $user->save();
                }

            } else{
                if (!empty($data['user_id'])){
                    $agentApply=AgentApply::where(['user_id'=>$data['user_id']])->find();
                    if (!$agentApply){
                        AgentApply::create($data);
                    }
                }

            }
        }
    }


    private function bindAgent(array $data, string $mid)
    {
        $find = Configuration::where(['mall_id' => $mid, 'type' => 'agentExplain'])->field('configuration')->find();
        if (!$find['configuration']['relationship']) {
            UserModel::update(['pid' => $data['pid']], ['id' => $data['id']]);
        }
    }

    private function subscribe(string $openid, array $js)
    {
        if (!Cache::store('redis')->has('TOKEN:' . $js['mid'])) {
            $token = Url::$TOKEN . "grant_type=client_credential&appid=" . $js['appid'] . "&secret=" . $js['appsecret'];
            $_js = http_curl($token);
            $js_token = json_decode($_js, true);
            if (array_key_exists('access_token', $js_token))
                Cache::store('redis')->set('TOKEN:' . $js['mid'], $_js, 7000);
            else
                throw new Exception('获取access_token异常', HTTP_INVALID);
        } else {
            $js_token = json_decode(Cache::store('redis')->get('TOKEN:' . $js['mid']), true);
        }
        $url = Url::$USERINFO_URL . "access_token=" . $js_token['access_token'] . "&openid=" . $openid . "&lang=zh_CN";
        $js1 = http_curl($url);

        $url = Url::$OAUTH_URL . $js['access_token'] . "&openid=" . $js['openid'] . "&lang=zh_CN";
        $res = http_curl($url);
        $data = json_decode($res, true);
        $data['subscribe'] = $js1['subscribe'] ?? 0;
        return $data;
    }

    private function updateSubscribe(string $openid, array $js, int $id)
    {
        $res = $this->subscribe($openid, $js);
        if (!empty($res['subscribe'])) User::update(['subscribe' => 1], ['id' => $id]);
    }

    private function setHeadUrl(string $url)
    {
        return substr($url, 4, 1) != 's' ? "https" . substr($url, 4) : $url;
    }

    public function logOn(array $data): array
    {
        $find = User::where('mall_id', $data['mall_id'])->where('mobile', $data['mobile'])->find();
        if (hash('sha256', $data['password']) !== $find['password'])
            throw new Exception('输入密码有误！', HTTP_INVALID);

        $data = $find->hidden(['password']);
        return [HTTP_SUCCESS, $data];
    }


    public function forgetPasswor(array $data)
    {
        $res = $this->verificationSmsCode($data['mobile'], $data['code']);
        if ($res[0] !== 200)
            throw  new Exception('验证码有误', HTTP_INVALID);

        $up = User::where('mall_id', $data['mall_id'])
            ->where('mobile', $data['mobile'])
            ->whereNotNull('password')
            ->update(['password' => hash('sha256', $data['password'])]);

        return [HTTP_SUCCESS, $up];
    }

}